/*
 * @Author: 0x9DEFA478
 * @Date: 2021-06-11 21:16:55
 * @LastEditTime: 2022-01-02 00:13:32
 * @LastEditors: 0x9DEFA478
 * @Description: PLL实现
 * QQ:2652450237
 * ============================================================================================================================================
 * 
 * 
 * 
 *                                                                                               ************      ****************************
 *                                                                                             ************      ****************************  
 *                                                                                           ************      ****************************    
 *                                                                                         ************      ****************************      
 *                                                                                       ************      ************                        
 *                                                                                     ************      ************                          
 *                                                                                   ************      ************                            
 *                                                                                 ************      ************                              
 *                                                                               ************      ************                                
 *                                                                             ************      ************                                  
 *                                                                           ************      ************                                    
 *                                                                         ************      ************                                      
 *                                                                       ************      ************                                        
 *                                                                     ************      ************                                          
 *                                                                   ************      ************                                            
 *                                                                 ************      ************                                              
 *                                                               ************      ************                                                
 *                                                             ************      ************                                                  
 *                                                           ************      ************                                                    
 *                                                         ************      ************                                                      
 *                                                       ************      ************                                                        
 *                                                     ************      ************                                                          
 *                                                   ************      ************                                                            
 *                                                 ************      ************                                                              
 *                                               ************      ************                                                                
 *                                             ************      ************                                                                  
 *                                           ************      ************                                                                    
 *                                         ************      ************                                                                      
 *                                       ************      ************                                                                        
 *                                     ************      ************                                                                          
 *                                   ************      ************                                                                            
 *                                 ************      ************                                                                              
 *                               ************      ************                                                                                
 *                             ************      ************                                                                                  
 *                           ************      ************                                                                                    
 *                         ************      ************                                                                                      
 *       ****************************      ************                                                                                        
 *     ****************************      ************                                                                                          
 *   ****************************      ************                                                                                            
 * ****************************      ************                                                                                              
 * 
 * 
 * 
 * ============================================================================================================================================
 * 
 */
#include "IP_PLL.h"
#include "stm32h7xx.h"



/**
 * @brief 使能或关闭PLL1
 * @param Status 0:关闭PLL 其他:打开PLL
 * @return 无
 */
void PLL1_SetStatus(unsigned int Status){

  if(Status){
    RCC->CR|=RCC_CR_PLL1ON;//使能pll1
    while(!(RCC->CR&RCC_CR_PLL1RDY)){
    }
  }
  else{
    RCC->CR&=~RCC_CR_PLL1ON;//失能pll1
    while(RCC->CR&RCC_CR_PLL1RDY){
    }
  }
}

/**
 * @brief 使能或关闭PLL2
 * @param Status 0:关闭PLL 其他:打开PLL
 * @return 无
 */
void PLL2_SetStatus(unsigned int Status){


  if(Status){
    RCC->CR|=RCC_CR_PLL2ON;//使能pll2
    while(!(RCC->CR&RCC_CR_PLL2RDY)){
    }
  }
  else{
    RCC->CR&=~RCC_CR_PLL2ON;//失能pll2
    while(RCC->CR&RCC_CR_PLL2RDY){
    }
  }
}

/**
 * @brief 使能或关闭PLL3
 * @param Status 0:关闭PLL 其他:打开PLL
 * @return 无
 */
void PLL3_SetStatus(unsigned int Status){


  if(Status){

    RCC->CR|=RCC_CR_PLL3ON;//使能pll2
    while(!(RCC->CR&RCC_CR_PLL3RDY)){
    }
  }
  else{
    RCC->CR&=~RCC_CR_PLL3ON;//失能pll2
    while(RCC->CR&RCC_CR_PLL3RDY){
    }
  }
}




/**
 * @brief PLL1输出控制 PLL1未开启时使用
 * @param pIsOutput p是否输出 0:不输出
 * @param qIsOutput q是否输出 0:不输出
 * @param rIsOutput r是否输出 0:不输出
 * @return 无
 */
void PLL1_SetOutput(unsigned int pIsOutput,unsigned int qIsOutput,unsigned int rIsOutput){

  if(RCC->CR&RCC_CR_PLL1ON){
  
    return;
  }

  if(pIsOutput){
    RCC->PLLCFGR|=RCC_PLLCFGR_DIVP1EN;
  }
  else{
    RCC->PLLCFGR&=(~RCC_PLLCFGR_DIVP1EN);
  }

  if(qIsOutput){
    RCC->PLLCFGR|=RCC_PLLCFGR_DIVQ1EN;
  }
  else{
    RCC->PLLCFGR&=(~RCC_PLLCFGR_DIVQ1EN);
  }

  if(rIsOutput){
    RCC->PLLCFGR|=RCC_PLLCFGR_DIVR1EN;
  }
  else{
    RCC->PLLCFGR&=(~RCC_PLLCFGR_DIVR1EN);
  }
}

/**
 * @brief PLL2输出控制 PLL2未开启时使用
 * @param pIsOutput p是否输出 0:不输出
 * @param qIsOutput q是否输出 0:不输出
 * @param rIsOutput r是否输出 0:不输出
 * @return 无
 */
void PLL2_SetOutput(unsigned int pIsOutput,unsigned int qIsOutput,unsigned int rIsOutput){

  if(RCC->CR&RCC_CR_PLL2ON){

    return;
  }

  if(pIsOutput){
    RCC->PLLCFGR|=RCC_PLLCFGR_DIVP2EN;
  }
  else{
    RCC->PLLCFGR&=(~RCC_PLLCFGR_DIVP2EN);
  }

  if(qIsOutput){
    RCC->PLLCFGR|=RCC_PLLCFGR_DIVQ2EN;
  }
  else{
    RCC->PLLCFGR&=(~RCC_PLLCFGR_DIVQ2EN);
  }

  if(rIsOutput){
    RCC->PLLCFGR|=RCC_PLLCFGR_DIVR2EN;
  }
  else{
    RCC->PLLCFGR&=(~RCC_PLLCFGR_DIVR2EN);
  }
}

/**
 * @brief PLL3输出控制 PLL3未开启时使用
 * @param pIsOutput p是否输出 0:不输出
 * @param qIsOutput q是否输出 0:不输出
 * @param rIsOutput r是否输出 0:不输出
 * @return 无
 */
void PLL3_SetOutput(unsigned int pIsOutput,unsigned int qIsOutput,unsigned int rIsOutput){

  if(RCC->CR&RCC_CR_PLL3ON){

    return;
  }

  if(pIsOutput){
    RCC->PLLCFGR|=RCC_PLLCFGR_DIVP3EN;
  }
  else{
    RCC->PLLCFGR&=(~RCC_PLLCFGR_DIVP3EN);
  }

  if(qIsOutput){
    RCC->PLLCFGR|=RCC_PLLCFGR_DIVQ3EN;
  }
  else{
    RCC->PLLCFGR&=(~RCC_PLLCFGR_DIVQ3EN);
  }

  if(rIsOutput){
    RCC->PLLCFGR|=RCC_PLLCFGR_DIVR3EN;
  }
  else{
    RCC->PLLCFGR&=(~RCC_PLLCFGR_DIVR3EN);
  }
}




/**
 * @brief 设置倍频器小数分频 
 * @param Fracn 倍频系数小数部分 0~8191
 * @return 无
 */
void PLL1_SetFracn(unsigned int Fracn){

  RCC->PLLCFGR&=~(RCC_PLLCFGR_PLL1FRACEN);//置0 PLL1FRACEN
  RCC->PLL1FRACR=(RCC->PLL1FRACR&(~RCC_PLL1FRACR_FRACN1_Msk))|(RCC_PLL1FRACR_FRACN1_Msk&(Fracn<<RCC_PLL1FRACR_FRACN1_Pos));
  RCC->PLLCFGR|=RCC_PLLCFGR_PLL1FRACEN;//置1 PLL1FRACEN
}

/**
 * @brief 设置倍频器小数分频 
 * @param Fracn 倍频系数小数部分 0~8191
 * @return 无
 */
void PLL2_SetFracn(unsigned int Fracn){

  RCC->PLLCFGR&=~(RCC_PLLCFGR_PLL2FRACEN);//置0 PLL2FRACEN
  RCC->PLL2FRACR=(RCC->PLL2FRACR&(~RCC_PLL2FRACR_FRACN2_Msk))|(RCC_PLL2FRACR_FRACN2_Msk&(Fracn<<RCC_PLL2FRACR_FRACN2_Pos));
  RCC->PLLCFGR|=RCC_PLLCFGR_PLL2FRACEN;//置1 PLL2FRACEN
}

/**
 * @brief 设置倍频器小数分频 
 * @param Fracn 倍频系数小数部分 0~8191
 * @return 无
 */
void PLL3_SetFracn(unsigned int Fracn){

  RCC->PLLCFGR&=~(RCC_PLLCFGR_PLL3FRACEN);//置0 PLL3FRACEN
  RCC->PLL3FRACR=(RCC->PLL3FRACR&(~RCC_PLL3FRACR_FRACN3_Msk))|(RCC_PLL3FRACR_FRACN3_Msk&(Fracn<<RCC_PLL3FRACR_FRACN3_Pos));
  RCC->PLLCFGR|=RCC_PLLCFGR_PLL3FRACEN;//置1 PLL3FRACEN
}




/**
 * @brief 配置PLL1 应该在PLL1失能的情况下使用该方法
 *        需要提供PLL参考时钟频率 以进行频率范围配置
 * @param pllSrcFreq PLL1参考频率 (pllm分频之前的)
 * @param pllm 预分频m
 * @param plln 倍频系数n
 * @param pllp 输出p的分频系数(对于PLL1 这个必须为偶数)
 * @param pllq 输出q的分频系数
 * @param pllr 输出r的分频系数
 * @return 无
 */
void PLL1_SetDIV(unsigned int pllSrcFreq,unsigned int pllm,unsigned int plln,unsigned int pllp,unsigned int pllq,unsigned int pllr){

  unsigned long long refFreq;
  unsigned long long vcoFreq;
  unsigned long long pllcfgr;

  if(RCC->CR&RCC_CR_PLL1ON){
    return;
  }

  RCC->PLLCKSELR=(RCC->PLLCKSELR&(~RCC_PLLCKSELR_DIVM1_Msk))|((pllm<<RCC_PLLCKSELR_DIVM1_Pos)&RCC_PLLCKSELR_DIVM1_Msk);

  RCC->PLL1DIVR = (RCC_PLL1DIVR_N1_Msk & ((plln-1) << RCC_PLL1DIVR_N1_Pos)) 
    |(RCC_PLL1DIVR_P1_Msk & ((pllp-1) << RCC_PLL1DIVR_P1_Pos))
    |(RCC_PLL1DIVR_Q1_Msk & ((pllq-1) << RCC_PLL1DIVR_Q1_Pos))
    |(RCC_PLL1DIVR_R1_Msk & ((pllr-1) << RCC_PLL1DIVR_R1_Pos));


  refFreq=pllSrcFreq/pllm;
  vcoFreq=(unsigned long long)pllSrcFreq*plln/pllm;

  pllcfgr=RCC->PLLCFGR;

	if(vcoFreq>420000000U){
		pllcfgr&=(~RCC_PLLCFGR_PLL1VCOSEL);//192~960MHz
	}else if(vcoFreq>=192000000U){
		if(refFreq>2000000U){
			pllcfgr&=(~RCC_PLLCFGR_PLL1VCOSEL);//192~960MHz
		}else{
			pllcfgr|=RCC_PLLCFGR_PLL1VCOSEL;//150~420M
		}
  }else{
    pllcfgr|=RCC_PLLCFGR_PLL1VCOSEL;//150~420M
  }

  if(refFreq>8000000U){
    pllcfgr=(pllcfgr&(~RCC_PLLCFGR_PLL1RGE_Msk))|(RCC_PLLCFGR_PLL1RGE_Msk&(0x03U<<RCC_PLLCFGR_PLL1RGE_Pos));//8~16MHz
  }else if(refFreq>4000000U){
    pllcfgr=(pllcfgr&(~RCC_PLLCFGR_PLL1RGE_Msk))|(RCC_PLLCFGR_PLL1RGE_Msk&(0x02U<<RCC_PLLCFGR_PLL1RGE_Pos));//4~8MHz
  }else if(refFreq>2000000U){
    pllcfgr=(pllcfgr&(~RCC_PLLCFGR_PLL1RGE_Msk))|(RCC_PLLCFGR_PLL1RGE_Msk&(0x01U<<RCC_PLLCFGR_PLL1RGE_Pos));//2~4MHz
  }else{
    pllcfgr=(pllcfgr&(~RCC_PLLCFGR_PLL1RGE_Msk))|(RCC_PLLCFGR_PLL1RGE_Msk&(0x00U<<RCC_PLLCFGR_PLL1RGE_Pos));//1~2MHz
  }

  RCC->PLLCFGR=pllcfgr;

}

/**
 * @brief 配置PLL2 应该在PLL2失能的情况下使用该方法
 *        需要提供PLL参考时钟频率 以进行频率范围配置
 * @param pllSrcFreq PLL2参考频率 (pllm分频之前的)
 * @param pllm 预分频m
 * @param plln 倍频系数n
 * @param pllp 输出p的分频系数
 * @param pllq 输出q的分频系数
 * @param pllr 输出r的分频系数
 * @return 无
 */
void PLL2_SetDIV(unsigned int pllSrcFreq,unsigned int pllm,unsigned int plln,unsigned int pllp,unsigned int pllq,unsigned int pllr){

  unsigned long long refFreq;
  unsigned long long vcoFreq;
  unsigned long long pllcfgr;

  if(RCC->CR&RCC_CR_PLL2ON){
    return;
  }

  RCC->PLLCKSELR=(RCC->PLLCKSELR&(~RCC_PLLCKSELR_DIVM2_Msk))|((pllm<<RCC_PLLCKSELR_DIVM2_Pos)&RCC_PLLCKSELR_DIVM2_Msk);

  RCC->PLL2DIVR = (RCC_PLL2DIVR_N2_Msk & ((plln-1) << RCC_PLL2DIVR_N2_Pos)) 
    |(RCC_PLL2DIVR_P2_Msk & ((pllp-1) << RCC_PLL2DIVR_P2_Pos))
    |(RCC_PLL2DIVR_Q2_Msk & ((pllq-1) << RCC_PLL2DIVR_Q2_Pos))
    |(RCC_PLL2DIVR_R2_Msk & ((pllr-1) << RCC_PLL2DIVR_R2_Pos));


  refFreq=pllSrcFreq/pllm;
  vcoFreq=(unsigned long long)pllSrcFreq*plln/pllm;

  pllcfgr=RCC->PLLCFGR;

  if(vcoFreq>420000000U){
		pllcfgr&=(~RCC_PLLCFGR_PLL1VCOSEL);//192~960MHz
	}else if(vcoFreq>=192000000U){
		if(refFreq>2000000U){
			pllcfgr&=(~RCC_PLLCFGR_PLL1VCOSEL);//192~960MHz
		}else{
			pllcfgr|=RCC_PLLCFGR_PLL1VCOSEL;//150~420M
		}
  }else{
    pllcfgr|=RCC_PLLCFGR_PLL1VCOSEL;//150~420M
  }

  if(refFreq>8000000U){
    pllcfgr=(pllcfgr&(~RCC_PLLCFGR_PLL2RGE_Msk))|(RCC_PLLCFGR_PLL2RGE_Msk&(0x03U<<RCC_PLLCFGR_PLL2RGE_Pos));//8~16MHz
  }else if(refFreq>4000000U){
    pllcfgr=(pllcfgr&(~RCC_PLLCFGR_PLL2RGE_Msk))|(RCC_PLLCFGR_PLL2RGE_Msk&(0x02U<<RCC_PLLCFGR_PLL2RGE_Pos));//4~8MHz
  }else if(refFreq>2000000U){
    pllcfgr=(pllcfgr&(~RCC_PLLCFGR_PLL2RGE_Msk))|(RCC_PLLCFGR_PLL2RGE_Msk&(0x01U<<RCC_PLLCFGR_PLL2RGE_Pos));//2~4MHz
  }else{
    pllcfgr=(pllcfgr&(~RCC_PLLCFGR_PLL2RGE_Msk))|(RCC_PLLCFGR_PLL2RGE_Msk&(0x00U<<RCC_PLLCFGR_PLL2RGE_Pos));//1~2MHz
  }

  RCC->PLLCFGR=pllcfgr;

}

/**
 * @brief 配置PLL3 应该在PLL3失能的情况下使用该方法
 *        需要提供PLL参考时钟频率 以进行频率范围配置
 * @param pllSrcFreq PLL3参考频率 (pllm分频之前的)
 * @param pllm 预分频m
 * @param plln 倍频系数n
 * @param pllp 输出p的分频系数
 * @param pllq 输出q的分频系数
 * @param pllr 输出r的分频系数
 * @return 无
 */
void PLL3_SetDIV(unsigned int pllSrcFreq,unsigned int pllm,unsigned int plln,unsigned int pllp,unsigned int pllq,unsigned int pllr){

  unsigned long long refFreq;
  unsigned long long vcoFreq;
  unsigned long long pllcfgr;

  if(RCC->CR&RCC_CR_PLL3ON){
    return;
  }

  RCC->PLLCKSELR=(RCC->PLLCKSELR&(~RCC_PLLCKSELR_DIVM3_Msk))|((pllm<<RCC_PLLCKSELR_DIVM3_Pos)&RCC_PLLCKSELR_DIVM3_Msk);

  RCC->PLL3DIVR = (RCC_PLL3DIVR_N3_Msk & ((plln-1) << RCC_PLL3DIVR_N3_Pos)) 
    |(RCC_PLL3DIVR_P3_Msk & ((pllp-1) << RCC_PLL3DIVR_P3_Pos))
    |(RCC_PLL3DIVR_Q3_Msk & ((pllq-1) << RCC_PLL3DIVR_Q3_Pos))
    |(RCC_PLL3DIVR_R3_Msk & ((pllr-1) << RCC_PLL3DIVR_R3_Pos));

  
  refFreq=pllSrcFreq/pllm;
  vcoFreq=(unsigned long long)pllSrcFreq*plln/pllm;

  pllcfgr=RCC->PLLCFGR;

  if(vcoFreq>420000000U){
		pllcfgr&=(~RCC_PLLCFGR_PLL1VCOSEL);//192~960MHz
	}else if(vcoFreq>=192000000U){
		if(refFreq>2000000U){
			pllcfgr&=(~RCC_PLLCFGR_PLL1VCOSEL);//192~960MHz
		}else{
			pllcfgr|=RCC_PLLCFGR_PLL1VCOSEL;//150~420M
		}
  }else{
    pllcfgr|=RCC_PLLCFGR_PLL1VCOSEL;//150~420M
  }

  if(refFreq>8000000U){
    pllcfgr=(pllcfgr&(~RCC_PLLCFGR_PLL3RGE_Msk))|(RCC_PLLCFGR_PLL3RGE_Msk&(0x03U<<RCC_PLLCFGR_PLL3RGE_Pos));//8~16MHz
  }else if(refFreq>4000000U){
    pllcfgr=(pllcfgr&(~RCC_PLLCFGR_PLL3RGE_Msk))|(RCC_PLLCFGR_PLL3RGE_Msk&(0x02U<<RCC_PLLCFGR_PLL3RGE_Pos));//4~8MHz
  }else if(refFreq>2000000U){
    pllcfgr=(pllcfgr&(~RCC_PLLCFGR_PLL3RGE_Msk))|(RCC_PLLCFGR_PLL3RGE_Msk&(0x01U<<RCC_PLLCFGR_PLL3RGE_Pos));//2~4MHz
  }else{
    pllcfgr=(pllcfgr&(~RCC_PLLCFGR_PLL3RGE_Msk))|(RCC_PLLCFGR_PLL3RGE_Msk&(0x00U<<RCC_PLLCFGR_PLL3RGE_Pos));//1~2MHz
  }

  RCC->PLLCFGR=pllcfgr;

}






